package unimelb.discussiontracker.twitter.service.integration;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import unimelb.discussiontracker.twitter.data.dao.IHashTagDao;
import unimelb.discussiontracker.twitter.data.dao.IIntervalDao;
import unimelb.discussiontracker.twitter.data.dao.ITweetDao;
import unimelb.discussiontracker.twitter.data.dao.ITweetRankingDao;
import unimelb.discussiontracker.twitter.data.dao.IUserDao;
import unimelb.discussiontracker.twitter.data.entity.HashTagEntity;
import unimelb.discussiontracker.twitter.data.entity.IntervalEntity;
import unimelb.discussiontracker.twitter.data.entity.RankType;
import unimelb.discussiontracker.twitter.data.entity.TopicEntity;
import unimelb.discussiontracker.twitter.data.entity.TweetEntity;
import unimelb.discussiontracker.twitter.data.entity.TweetHashTagAssociation;
import unimelb.discussiontracker.twitter.data.entity.TweetRanking;
import unimelb.discussiontracker.twitter.data.entity.TweetUserAssociation;
import unimelb.discussiontracker.twitter.data.entity.UserEntity;

public class TopTweetParser extends AbstractFileProcessor {
    private static final Logger logger = Logger.getLogger(TopTweetParser.class);

    private RankType rankType;

    private IIntervalDao intervalDao;

    private ITweetDao tweetDao;

    private IUserDao userDao;

    private IHashTagDao hashTagDao;

    private ITweetRankingDao tweetRankingDao;

    public void setRankType(RankType rankType) {
        this.rankType = rankType;
    }

    public void setIntervalDao(IIntervalDao intervalDao) {
        this.intervalDao = intervalDao;
    }

    public void setTweetDao(ITweetDao tweetDao) {
        this.tweetDao = tweetDao;
    }

    public void setUserDao(IUserDao userDao) {
        this.userDao = userDao;
    }

    public void setHashTagDao(IHashTagDao hashTagDao) {
        this.hashTagDao = hashTagDao;
    }

    public void setTweetRankingDao(ITweetRankingDao tweetRankingDao) {
        this.tweetRankingDao = tweetRankingDao;
    }

    @Override
    protected void processLine(String line, TopicEntity masterTopic) {
        try {
            final String[] tokens = line.split(" ", 9);
            
            if (tokens.length != 9) {
                logger.error("Invalid line:" + line);
                return;
            }

            final Date start = dateFormat.parse(tokens[0]);
            final Date end = dateFormat.parse(tokens[1]);
            final int strength = Integer.parseInt(tokens[2]);
            final int sentiment = Integer.parseInt(tokens[3]);

            final long userId = Long.parseLong(tokens[5]);
            final String userName = tokens[6];

            final long tweetId = Long.parseLong(tokens[4]);
            final long tweetTime = Long.parseLong(tokens[7]);
            final String text = tokens[8];
            
            if (text.length() > 255) {
                logger.error("Invalid line:" + line);
                return;
            }

            UserEntity owner = userDao.findById(userId);
            if (owner == null) {
                owner = new UserEntity();
                owner.setId(userId);
                owner.setName(userName);

                userDao.save(owner);
            }

            TweetEntity tweet = tweetDao.findById(tweetId);
            if (tweet == null) {
                tweet = new TweetEntity();
                tweet.setId(tweetId);
                tweet.setText(text);
                tweet.setCreatedDate(new Date(tweetTime));
                tweet.setOwner(owner);
                tweet.setHashTags(constructHashTagAssociation(tweet));
                tweet.setMentionedUsers(constructUserAssociation(tweet));

                tweetDao.save(tweet);
            }

            final IntervalEntity interval = intervalDao.findByStartEnd(start, end);

            TweetRanking tweetRanking = tweetRankingDao.findRankingsByTweetTopicAndIntervalId(tweetId, masterTopic.getId(), interval.getId(), rankType);
            if (tweetRanking == null) {
                tweetRanking = new TweetRanking();
                tweetRanking.setTweet(tweet);
                tweetRanking.setTopic(masterTopic);
                tweetRanking.setInterval(interval);
                tweetRanking.setSentiment(sentiment);
                tweetRanking.setStrength(strength);
                tweetRanking.setType(rankType);

                tweetRankingDao.save(tweetRanking);
            } else {
                tweetRanking.setSentiment(sentiment);
                tweetRanking.setStrength(strength);

                tweetRankingDao.update(tweetRanking);
            }
        } catch (Exception e) {
            logger.error("Invalid line:" + line, e);
        }
    }

    private List<TweetHashTagAssociation> constructHashTagAssociation(TweetEntity tweet) {
        final List<TweetHashTagAssociation> assocs = new ArrayList<TweetHashTagAssociation>();

        final Matcher matcher = Pattern.compile("#(\\w+)").matcher(tweet.getText());
        while (matcher.find()) {
            final String tagValue = matcher.group().substring(1);
            HashTagEntity hashTag = hashTagDao.findByValue(tagValue);
            if (hashTag == null) {
                hashTag = new HashTagEntity();
                hashTag.setValue(tagValue);

                hashTagDao.save(hashTag);
            }

            final TweetHashTagAssociation assoc = new TweetHashTagAssociation();
            assoc.setTweet(tweet);
            assoc.setHashTag(hashTag);
            assoc.setStartIndex(matcher.start());
            assoc.setEndIndex(matcher.end());

            assocs.add(assoc);
        }

        return assocs;
    }

    private List<TweetUserAssociation> constructUserAssociation(TweetEntity tweet) {
        final List<TweetUserAssociation> assocs = new ArrayList<TweetUserAssociation>();

        final Matcher matcher = Pattern.compile("@(\\w+)").matcher(tweet.getText());
        while (matcher.find()) {
            final String username = matcher.group().substring(1);
            UserEntity user = userDao.findByName(username);
            if (user != null) {
                final TweetUserAssociation assoc = new TweetUserAssociation();
                assoc.setTweet(tweet);
                assoc.setUser(user);
                assoc.setStartIndex(matcher.start());
                assoc.setEndIndex(matcher.end());

                assocs.add(assoc);
            }
        }

        return assocs;
    }
}
